Skip to content

[None][perf] wrap up eagle changes in m3 side branch - #18066

Merged
zheyuf merged 18 commits into
NVIDIA:feat/m3_with_msafrom
zheyuf:perf/minimax-m3-native-p128-draft
Sep 4, 2026
Merged

[None][perf] wrap up eagle changes in m3 side branch#18066
zheyuf merged 18 commits into
NVIDIA:feat/m3_with_msafrom
zheyuf:perf/minimax-m3-native-p128-draft

Conversation

@zheyuf

@zheyuf zheyuf commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR does all followings things in one PR to wrap up eagle works:

  1. [perf] change from default seperate draft/target kv manager to unified manager in aggregated serving attention DP off. This reduce the overhead of maintaining two kv manager, which brings 1.4-6.1% perf gain in X axis and 0.3-1.8% in Y axis across all points in agg. Also, TTFT is shrinked by 3-13%.
  2. [perf] switch from previous tpb 32 workaround to native tpb 128. Perf is neutral or have mini perf gain (~0.5%) .
  3. [fix] Fix an Eagle3 acceptance-length regression under piecewise torch.compile with max_num_streams > 1: the multi-stream scheduler could emit the last hidden-state capture after the graph output, so the drafter read a stale slice (disagg AL 3.25 -> 3.48; aggregated + PCG 2.98 -> 3.49). Fixed in auto_multi_stream.py; the earlier event-based publication path never executed and has been removed.
  4. [CI] Switch the CI from MHA eagle head to GQA eagle head.
  5. [chore] Clean up lots of unreachable code path. (P32 adapter stack and unreachable NVFP4 dense-decode
    paths)

After this PR, the agg pareto curve change from green curve to red curve. But this PR is not expected to boost perf for disagg.
image

Correctness

Case Job Acceptance rate Mean AL Result
Disaggregated, 1x CTX TP2 -> 1x GEN TP4, ADP off 2878351 0.828 3.485 PASS
Disaggregated, 1x CTX TP2 -> 1x GEN DEP8, ADP on 2878353 0.827 3.480 PASS
Aggregate, TP4, ADP off 2878354 0.832 3.497 PASS
Aggregate, TP4/EP4, ADP on 2878591 0.835 3.504 PASS

AgentX Agg pareto perf testing

Point X Y TTFT delta
TP8/C5 +1.44% +0.36% -6.40%
TP4/C15 +3.44% +1.55% -13.33%
TP4/C30 +6.11% +1.55% -5.92%
TP2/C30 +2.73% +1.89% -3.68%
Four-point geometric mean +3.42% +1.34% -7.41%

zheyuf added 7 commits August 17, 2026 22:55
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Both arms now run Inferact/MiniMax-M3-EAGLE3-GQA, the head production
is moving to: same training data as the MHA head with the drafter's
attention changed from 64 to 4 KV heads, so its draft KV cache is 16x
smaller and matches the target's head count.

Measured on this branch (4-GPU node, InferenceMAX eval + the shared
chat-GSM8K acceptance probe):

  aggregated  (separate draft manager)  3.515 / 0.838, accuracy 95.45
  disaggregated (unified sub-page view) 3.369 / 0.790, accuracy 95.15
                                        3.395 / 0.798, accuracy 95.45

The aggregated figure is indistinguishable from the MHA card's GSM8K
reference (3.518 / 0.839), which is why that reference stands in for
the GQA card's missing GSM8K entry; the two cards agree on the
benchmark they do share (MT-Bench 2.698 vs 2.668). The disaggregated
arm measures ~0.14 lower, so the rate floor drops 0.78 -> 0.76 for
headroom while the length floor stays at 3.3 — still between the
measured healthy range and the 3.33 plateau a drafter-KV transfer
regression produced on this workload.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
(cherry picked from commit af6ddb1)
Make graph exit depend on the latest mutation of every in-place target, including void side effects that are not reachable from the FX return value. This prevents an auxiliary-stream Eagle hidden-state capture from racing the graph-external speculative worker.

Add a structural scheduler test covering the event and wait inserted before graph output.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf
zheyuf force-pushed the perf/minimax-m3-native-p128-draft branch from 6d627d7 to e7c9ec9 Compare August 24, 2026 22:17
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf zheyuf added the api-compatible Accepted LLM API contract change that is backwards-compatible label Aug 24, 2026
zheyuf added 3 commits August 26, 2026 15:35
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf
zheyuf force-pushed the perf/minimax-m3-native-p128-draft branch from 38437d9 to 6ac0cb8 Compare August 27, 2026 00:02
zheyuf and others added 5 commits August 28, 2026 17:12
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
MiniMaxM3DraftKVCacheView required the shared pool's page-index scale to
equal the draft layer's flat-pool slot stride, then reused that pool-level
scale for its own block table. The pool scale counts the pool's first
layer's pages per slot, so on the hybrid NVFP4 KV cache (NVFP4 sparse
target layers plus the dense FP8 draft layer) the two differ: the AgentX
CTX TP2 geometry reports index_scale 171 against a draft slot stride of 8,
and every worker failed at warmup with "native P128 draft block-table
mapping is unavailable".

The view is rooted at the draft layer's K page, and get_kv_subpage_pool
already returns the layer-local stride that puts slot s's K at s * stride
and its V at s * stride + 1. Use that stride as the view's index scale and
drop the pool-scale equality check; the single-layer, P128, kv_offset == 1
and stream checks remain. Uniform pools yield the same value as before, so
homogeneous configurations are unchanged.

The hybrid-view unit test now gives the source pool a scale that differs
from the draft stride, and the geometry rejection test covers kv_offset.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Remove code that the native P128 draft view made unreachable or redundant:

- MiniMaxM3KVCacheManagerV2 no longer declares draft_manager_kv_cache_dtype
  or supports_shared_draft_layers; the executor forces the unified target
  cache for MiniMax-M3, so no separate draft manager is ever built, and the
  base class already defaults to shared draft layers.
- KvCacheCreator drops the draft_manager_tokens_per_block hook, which has
  no remaining definer.
- MiniMaxM3DraftKVCacheView.copy_batch_block_offsets keeps the V2 padding
  as is instead of clamping padded V entries to slot 0's V page; both
  choices address the same valid slot-0 memory, and the clamp cost one
  kernel launch per draft step.
- _dense_kv_inputs returns only the query, pool and slot stride; the
  softmax scales are constants at the call site.
- The view's error messages use the same "native P128 draft view" name as
  its docstring and startup log.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Every multi-stream runtime op (set_stream, record_event, wait_event,
record_stream) is gated by do_multi_stream(), which only the CUDA-graph
runner enables during capture. A disaggregated context worker runs the
piecewise torch.compile path without the CUDA-graph runner, so the flag
is never set there: a probe on the production MiniMax-M3 context config
showed set_stream, eagle_hidden_states_copy and
wait_for_captured_hidden_states all executing with do_multi_stream=False.
The publication event was therefore never recorded or waited on, and the
extra custom op, event plumbing, private config flag and scheduler
priority edge had no runtime effect. Remove them; the last capture goes
back through inplace_slice_copy like the others.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf zheyuf changed the title [None][perf] Use native P128 MiniMax-M3 draft KV pages [None][perf] wrapping up eagle changes in m3 side branch Sep 2, 2026
@zheyuf
zheyuf marked this pull request as ready for review September 2, 2026 22:29
@zheyuf
zheyuf requested review from a team as code owners September 2, 2026 22:29
@zheyuf

zheyuf commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #71084 [ run ] triggered by Bot. Commit: cde7b84 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #71084 [ run ] completed with state SUCCESS. Commit: cde7b84
/LLM/main/L0_MergeRequest_PR pipeline #58236 completed with status: 'SUCCESS'

CI Report

Link to invocation

@zheyuf zheyuf changed the title [None][perf] wrapping up eagle changes in m3 side branch [None][perf] wrap up eagle changes in m3 side branch Sep 3, 2026
@peihu-nv

peihu-nv commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator
  1. Our CTX configs use PCG with max_num_streams: 3. Could you confirm where standalone PCG enables with_multi_stream(True)? Otherwise, the stream/event operations seem to remain no-ops. It would also be helpful to add a test confirming that auxiliary streams and the event record/wait are exercised.

  2. We also use PCG in aggregated serving. Could you check whether the cache-transceiver requirement should be removed from hidden-state publication so it covers both aggregated and disaggregated Eagle3 PCG?

The multi-stream scheduler rebuilds the FX graph from its stream assignment.
An in-place op that mutates a graph input without returning a value (Eagle3
captures decoder hidden states into a preallocated buffer with
inplace_slice_copy) has no path to the FX output, so the scheduler could emit
it after the output node, where it is dead code once the module is
recompiled. On the MiniMax-M3 disaggregated context worker (piecewise
torch.compile, max_num_streams 3) this dropped the final hidden-state capture
and lowered Eagle3 acceptance from 3.48 to 3.24 on GSM8K; aggregated serving
with the same compile settings measured 2.98.

Make graph exit depend on the last mutation of every in-place target. The
mutation is then emitted before output, and when auxiliary streams are live
the exit also waits on the mutating stream before a graph-external consumer
reads the buffer. This replaces the Eagle-specific priority edge with a
general dependency and needs no model-specific op, event or configuration
gate.

Restore the scheduler unit test and extend it to assert that every capture
precedes output, including captures of the last decoder layer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf
zheyuf force-pushed the perf/minimax-m3-native-p128-draft branch from a3abd6e to 343310a Compare September 3, 2026 23:06
@zheyuf

zheyuf commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

@peihu-nv Both points are right, thanks — they led to the actual root cause.

  1. Nothing on the PCG path enables with_multi_stream(True)so I removed the non-ops. One thing I want to point out is that it seems like max_num_streams > 1 has no runtime effect in PCG, on this branch and on main (looks like a incomplete feature in main). So our CTX configs with max_num_streams: 3 get no perf gain from it.

  2. Thanks for pointing this out. Following your comment I found my previous AL fix in this PR was wrong. I deleted the publication path and added a new commit 343310a to fix the AL in the right way.

@zheyuf

zheyuf commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #71362 [ run ] triggered by Bot. Commit: 343310a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #71362 [ run ] completed with state SUCCESS. Commit: 343310a
/LLM/main/L0_MergeRequest_PR pipeline #58483 completed with status: 'SUCCESS'

CI Report

Link to invocation

@zheyuf
zheyuf merged commit 95ea460 into NVIDIA:feat/m3_with_msa Sep 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-compatible Accepted LLM API contract change that is backwards-compatible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants